/**
 * 
 */
package easyservice.network;

import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;

import easyservice.EasyServiceException;
import easyservice.interpreter.CommandInterpreter;
import easyservice.protocol.Command;

/**
 * TODO doc
 * 
 * @author Rodrigo Barbosa Lira
 * 
 */
public class XMPPServerNetworkAgent implements ServerNetworkAgent {
	
	private static Log log = LogFactory.getLog(XMPPServerNetworkAgent.class);

	private XMPPConnection connection;

	private NetworkListener networkListener;

	public XMPPServerNetworkAgent(String username, String password,
			String hostUrl, int hostPort, NetworkListener networkListener) {

//		XMPPConnection.DEBUG_ENABLED = true;
		this.networkListener = networkListener;
		
		try {
			log.info("Configuring connection");
			ConnectionConfiguration config = new ConnectionConfiguration(hostUrl, hostPort);
			connection = new XMPPConnection(config);
			
			log.info("Connecting");
			connection.connect();
			
			log.info("Identifying \"server\" user");
			connection.login(username, password);
		
		} catch (XMPPException e) {
			log.error("Error on connection", e);
			throw new EasyServiceException(e);
		}

		// think about it.
		startServer();
	}

	private void startServer() {
		log.info("Set status to available");
		connection.sendPacket(new Presence(Presence.Type.available));

		log.info("Create a packet filter to listen for new messages");
		PacketFilter filter = new PacketTypeFilter(Message.class);

		log.info("Register a packet collector using the filter we've created");
		connection.createPacketCollector(filter);

		log.info("Create a packet listener");
		PacketListener myListener = new PacketListener() {
			public void processPacket(Packet packet) {
				log.info("Retrieving packet received");
				Message m = (Message) packet;
				
				log.info("Interpreting received message");
				Command command = CommandInterpreter.interpret(m.getBody());
				
				log.info("Processing response message");
				Command result = networkListener.onReceiveMessage(command);
				
				log.debug("To: " + packet.getFrom() + "; Body: " + result.generatedString() + ";");
				Message message = new Message();
				message.setTo(packet.getFrom());
				message.setBody(result.generatedString());
				
				log.info("Sending packet");
				connection.sendPacket(message);
			}
		};
		
		log.info("Register the listener.");
		connection.addPacketListener(myListener, filter);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see easyservice.network.ServerNetworkAgent#sendMessageToClients(java.lang.String)
	 */
	@Override
	public void sendMessageToClients(String message) throws XMPPException {
		log.info("Sending message to clients");
		Roster roster = connection.getRoster();
		
		Collection<RosterEntry> entries = roster.getEntries();
		log.debug("Connected clients: " + entries.size());
		log.debug("Message: " + message);
		
		Message msg;
		
		for (RosterEntry entry : entries) {
			msg = new Message();
			msg.setTo(entry.getUser());
			log.debug("Destination: " + entry.getUser());
			msg.setBody(message);
			connection.sendPacket(msg);
		}
	}
}